import {Layout} from '../../src/Layout';
export default Layout;

import {Card, CardPreview, Content, Image, Text, InlineAlert, Heading} from '@react-spectrum/s2';
import docs from 'docs:react-aria-components';
import {Button as VanillaButton} from 'vanilla-starter/Button';
import {Button as TailwindButton} from 'tailwind-starter/Button';
/* import {Button as MacroButton} from './ButtonExample'; */
import vanillaDocs from 'docs:vanilla-starter/Button';
import tailwindDocs from 'docs:tailwind-starter/Button';
import '../../tailwind/tailwind.css';
import typesDocs from 'docs:@react-types/shared/src/events.d.ts';

export const tags = ['btn'];
export const relatedPages = [{'title': 'useButton', 'url': 'Button/useButton.html'}];
export const description = 'Allows a user to perform an action, with mouse, touch, and keyboard interactions.';

# Button

<PageDescription>{docs.exports.Button.description}</PageDescription>

<ExampleSwitcher examples={['Vanilla CSS', 'Tailwind'/*, 'Style Macro'*/]}>
  <VisualExample
    component={VanillaButton}
    docs={vanillaDocs.exports.Button}
    links={vanillaDocs.links}
    props={['variant', 'isPending', 'isDisabled']}
    initialProps={{children: 'Press me'}}
    type="vanilla"
    files={["starters/docs/src/Button.tsx", "starters/docs/src/Button.css"]} />
  <VisualExample
    component={TailwindButton}
    docs={tailwindDocs.exports.Button}
    links={tailwindDocs.links}
    props={['variant', 'isPending', 'isDisabled']}
    initialProps={{children: 'Press me'}}
    type="tailwind"
    files={["starters/tailwind/src/Button.tsx"]} />
  {/* <VisualExample
    component={MacroButton}
    docs={docs.exports.Button}
    links={docs.links}
    props={['isDisabled']}
    initialProps={{children: 'Style Macro'}}
    files={["packages/dev/s2-docs/pages/ButtonExample.tsx"]} /> */}
</ExampleSwitcher>

## Events

Use the `onPress` prop to handle interactions via mouse, keyboard, and touch. This is similar to `onClick`, but normalized for consistency across browsers, devices, and interaction methods. Read our [blog post](blog/building-a-button-part-1) to learn more.

The `onPressStart`, `onPressEnd`, and `onPressChange` events are also emitted as the user interacts with the button. Each of these handlers receives a <TypeLink links={typesDocs.links} type={typesDocs.exports.PressEvent} />, which provides information about the target and interaction method. See [usePress](usePress) for more details.

```tsx render
"use client";
import {Button} from 'vanilla-starter/Button';
import {useState} from 'react';

function Example() {
  let [pointerType, setPointerType] = useState('');

  return (
    <>
      <Button
        /*- begin highlight -*/
        onPressStart={e => setPointerType(e.pointerType)}
        onPressEnd={() => setPointerType('')}>
        {/*- end highlight -*/}
        Press me
      </Button>
      <p>{pointerType ? `You are pressing the button with a ${pointerType}!` : 'Ready to be pressed.'}</p>
    </>
  );
}
```

## Pending

Use the `isPending` prop to display a pending state. Pending buttons remain focusable, but are otherwise disabled. Pending state changes are announced to assistive technologies.

```tsx render
"use client";
import {Button} from 'vanilla-starter/Button';
import {useState} from 'react';

function PendingButton() {
  let [isPending, setPending] = useState(false);

  return (
    <Button
      ///- begin highlight -///
      isPending={isPending}
      ///- end highlight -///
      onPress={() => {
        setPending(true);
        setTimeout(() => {
          setPending(false);
        }, 5000);
      }}>
      Save
    </Button>
  );
}
```

<InlineAlert variant="notice">
  <Heading>Accessibility</Heading>
  <Content><p style={{marginTop: 0}}>The `ProgressBar` must be in the accessibility tree as soon as the button becomes pending, even if it is not visible. To delay showing a spinner until a minimum amount of time passes, use `opacity: 0`. Do not use `visibility: hidden` or `display: none` as these remove the element from the accessibility tree.</p>
  <p style={{marginBottom: 0}}>To reserve space for the button's label while pending, either set it to `visibility: hidden` with a descriptive ProgressBar `aria-label` (e.g. "Saving"), or set it to `opacity: 0` to combine the button's label with the `aria-label` of the ProgressBar (e.g. "Save, pending").</p></Content>
</InlineAlert>

## Link buttons

The `Button` component always represents a button semantically. To create a link that visually looks like a button, use the [Link](Link) component instead. You can reuse the same styles you apply to the `Button` component on the `Link`.

```tsx render
"use client";
import {Link} from 'react-aria-components';

<Link className="react-aria-Button button-base" href="https://adobe.com/" target="_blank">
  Adobe
</Link>
```

## Examples

<ExampleList tag="button" pages={props.pages} />

## API

<PropTable component={docs.exports.Button} links={docs.links} />
